package com.zhongan.gateway.filter;

import java.io.IOException;
import java.io.OutputStream;
import java.util.Date;
import java.util.UUID;

import javax.annotation.Resource;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.task.TaskExecutor;
import org.springframework.stereotype.Component;

import com.alibaba.fastjson.JSONObject;
import com.netflix.zuul.context.RequestContext;
import com.zhongan.gateway.bean.Api;
import com.zhongan.gateway.bean.ApiRequestLog;
import com.zhongan.gateway.bean.Developer;
import com.zhongan.gateway.common.constant.GwDeveloperApiConstant;
import com.zhongan.gateway.common.enums.GatewayErrorCodeEnum;
import com.zhongan.gateway.common.enums.ResponseCodeEnum;
import com.zhongan.gateway.common.utils.TypeUtil;
import com.zhongan.gateway.dto.RequestBase;
import com.zhongan.gateway.dto.ResponseBase;
import com.zhongan.gateway.service.ApiLogService;
import com.zhongan.gateway.service.MongoService;

/**
 */
@Component
public class PrintResFilter implements Filter {

    private Logger        logger = LoggerFactory.getLogger(PrintResFilter.class);

    //    private Logger        monitorLog = LoggerFactory.getLogger("MonitorLog");

    @Value("${spring.cloud.config.name}")
    private String        appName;
    @Value("${application.mongo.mongoSwitch}")
    private String        mongoSwitch;
    @Resource
    private ApiLogService apiLogService;

    @Resource
    private TaskExecutor  taskExecutor;

    @Resource
    private MongoService  mongoService;

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException,
            ServletException {

        HttpServletRequest req = (HttpServletRequest) request;

        String uuid = UUID.randomUUID().toString();
        req.setAttribute("uuid", uuid);
        MDC.put("uuid", uuid);

        //统计时间
        long start = System.currentTimeMillis();
        //跨域
        //        setAccessControl((HttpServletResponse) response);
        //调用zuulFilter
        chain.doFilter(request, response);

        ResponseBase rb = (ResponseBase) request.getAttribute("responseBase");

        //没有返回值则为异常情况
        if (null == rb) {
            rb = new ResponseBase();
            rb.setTimestamp(System.currentTimeMillis() + "");
            //校验未通过异常
            rb.setCode(GatewayErrorCodeEnum.UN_KNOWN.getCode());
            rb.setMessage(GatewayErrorCodeEnum.UN_KNOWN.getMsg());
        } else {
            saveLog(start, uuid, rb, req);
        }
        HttpServletResponse res = (HttpServletResponse) response;
        String uri = req.getRequestURI();
        if (uri != null && uri.startsWith(GwDeveloperApiConstant.COMMON_GROOVY_URL)) {
            //返回返回值
            printGroovyRes(rb, res);
        } else {
            //返回返回值
            printRes(rb, req, res);
        }

        //清空context
        RequestContext.getCurrentContext().unset();
        logger.info("api流程结束...");
    }

    private void printGroovyRes(ResponseBase rb, HttpServletResponse response) throws IOException {

        String res = "";
        if (null == rb.getBizContent()) {
            res = rb.getMessage();
        } else {
            res = JSONObject.toJSONString(rb.getBizContent());
        }
        response.setContentType("application/json");
        response.setCharacterEncoding("utf-8");

        OutputStream os = response.getOutputStream();
        try {
            os.write(res.getBytes());
        } catch (IOException e) {
            logger.error("输出返回值失败，" + e.getMessage(), e);
        }
    }

    private void printRes(ResponseBase rb, HttpServletRequest req, HttpServletResponse response) throws IOException {
        //        if ("N".equals(codeFlag)) {
        //            //福顺接口不需要code;
        //            rb.setCode(null);
        //        }

        String res = JSONObject.toJSONString(rb);
        response.setContentType("application/json");
        response.setCharacterEncoding("utf-8");
        //        Integer code = (Integer) req.getAttribute("res_status");
        //        if (null == code) {
        //            response.setStatus(502);
        //        } else {
        //            response.setStatus(code);
        //        }
        OutputStream os = response.getOutputStream();
        try {
            os.write(res.getBytes());
        } catch (IOException e) {
            logger.error("输出返回值失败，" + e.getMessage(), e);
        }
    }

    //    private void setAccessControl(HttpServletResponse httpResponse) {
    //        httpResponse.setHeader("Access-Control-Allow-Origin", "*");
    //        httpResponse.setHeader("Access-Control-Allow-Headers", "x-requested-with,content-type");
    //    }

    private void saveLog(long start, String uuid, ResponseBase rb, HttpServletRequest request) {
        RequestBase re = (RequestBase) request.getAttribute("requestBase");
        Api api = (Api) request.getAttribute("api");
        Developer developer = (Developer) request.getAttribute("developer");
        String responseClear = (String) request.getAttribute("responseClear");
        if (null == api || null == developer) {
            logger.info("请求非法,不记录日志...");
            return;
        }

        //日志
        ApiRequestLog log = new ApiRequestLog();
        //监控log
        //        JSONObject json = new JSONObject();
        long timecost = System.currentTimeMillis() - start;

        log.setAppKey(re.getAppKey());
        log.setServiceName(re.getServiceName());
        log.setTimeCost((int) timecost);
        log.setTimestamp(re.getTimestamp());
        log.setUuid(uuid);
        log.setVersion(re.getVersion());
        log.setGmtCreated(new Date());
        log.setSignType(developer.getEncryptType());
        //            log.setRequestClear(re.getBizContent().toString());
        log.setRequestInfo(getMsg(re.getBizContent()));
        log.setResponseInfo(getMsg(responseClear));
        //            log.setResponseInfo(getMsg(rb));

        if (ResponseCodeEnum.SUCCESS.getCode().equals(rb.getCode())
                || ResponseCodeEnum.SUCCESS_QUERY.getCode().equals(rb.getCode())) {
            log.setIsSuccess("Y");
            //            json.put("status", 0);
        } else {
            log.setIsSuccess("N");
            //            json.put("status", -1);
        }

        try {
            taskExecutor.execute(new Runnable() {
                public void run() {
                    logger.info("开始记录日志...");
                    if ("Y".equals(mongoSwitch)) {
                        mongoService.insertOne(log);
                    } else {
                        apiLogService.insertLog(log);
                    }
                    logger.info("结束记录日志...");
                }
            });

        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }

        //            json.put("appKey", re.getAppKey());
        //            json.put("serviceName", re.getServiceName());
        //            json.put("type", "applog");
        //            json.put("category", appName);
        //            json.put("subCatagory", developer.getDevName());
        //            json.put("operateType", appName);
        //            json.put("devGroup", api.getDevGroup());
        //            json.put("timeCost", timecost);
        //            monitorLog.info(json.toJSONString());

    }

    private String getMsg(Object msg) {
        String s = TypeUtil.obj2Str(msg);

        if (null != s && s.length() > 5000) {
            s = s.substring(0, 5000);
        }
        return s;
    }

    @Override
    public void destroy() {

    }

    @Override
    public void init(FilterConfig arg0) throws ServletException {

    }

}
